﻿using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using System;
using System.Security.Cryptography;
using System.Text;

namespace TongueClassLibrary
{
    class RSAUtil
    {
        /// <summary>
        /// 使用公钥加密
        /// </summary>
        /// <returns></returns>
        public static string encrypt(string strText, string strPublicKey)
        {
            /**
             * C#中RSA公钥和私钥的格式都是XML的，而在其他语言如java中，生成的RSA密钥就是普通的Base64字符串
             * 参照：https://www.cnblogs.com/Laggage/p/11028614.html
             */
            string xmlPublicKey = toXmlPublicKey(strPublicKey);

            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(xmlPublicKey);
            byte[] byteText = Encoding.UTF8.GetBytes(strText);
            byte[] byteEntry = rsa.Encrypt(byteText, false);
            return Convert.ToBase64String(byteEntry);
        }

        /// <summary>
        /// 私钥解密
        /// </summary>
        /// <param name="strEntryText"></param>
        /// <param name="strPrivateKey"></param>
        /// <returns></returns>
        public static string decrypt(string strEntryText, string strPrivateKey)
        {
            string xmlPrivateKey = toXmlPrivateKey(strPrivateKey);

            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(xmlPrivateKey);
            byte[] byteEntry = Convert.FromBase64String(strEntryText);
            byte[] byteText = rsa.Decrypt(byteEntry, false);
            return Encoding.UTF8.GetString(byteText);
        }

        /// <summary>
        /// 加签
        /// </summary>
        /// <param name="strText"></param>
        /// <param name="strPrivateKey"></param>
        /// <returns></returns>
        public static string sign(string strText, string strPrivateKey)
        {
            string xmlPrivateKey = toXmlPrivateKey(strPrivateKey);

            byte[] byteText = Encoding.UTF8.GetBytes(strText);

            // java端采用的是md5 hash算法
            var md5 = new MD5CryptoServiceProvider();
            byte[] rgbHash = md5.ComputeHash(byteText);

            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(xmlPrivateKey);
            RSAPKCS1SignatureFormatter formatter = new RSAPKCS1SignatureFormatter(rsa);

            formatter.SetHashAlgorithm("MD5");
            byte[] inArray = formatter.CreateSignature(rgbHash);
            return Convert.ToBase64String(inArray);
        }

        /// <summary>
        /// 验证
        /// </summary>
        /// <param name="strText"></param>
        /// <param name="signText"></param>
        /// <param name="strPublicKey"></param>
        /// <returns></returns>
        public static bool verify(string strText, string signText, string strPublicKey)
        {
            try
            {
                string xmlPublicKey = toXmlPublicKey(strPublicKey);

                byte[] byteText = Encoding.UTF8.GetBytes(strText);

                var md5 = new MD5CryptoServiceProvider();
                byte[] rgbHash = md5.ComputeHash(byteText);

                RSACryptoServiceProvider key = new RSACryptoServiceProvider();
                key.FromXmlString(xmlPublicKey);
                RSAPKCS1SignatureDeformatter deformatter = new RSAPKCS1SignatureDeformatter(key);

                deformatter.SetHashAlgorithm("MD5");
                byte[] rgbSignature = Convert.FromBase64String(signText);
                if (deformatter.VerifySignature(rgbHash, rgbSignature))
                {
                    return true;
                }
                return false;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 将字符串私钥转换为xml私钥
        /// </summary>
        /// <param name="privateKey"></param>
        /// <returns></returns>
        private static string toXmlPrivateKey(string privateKey)
        {
            RsaPrivateCrtKeyParameters privateKeyParams =
                PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey)) as RsaPrivateCrtKeyParameters;
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
            {
                RSAParameters rsaParams = new RSAParameters()
                {
                    Modulus = privateKeyParams.Modulus.ToByteArrayUnsigned(),
                    Exponent = privateKeyParams.PublicExponent.ToByteArrayUnsigned(),
                    D = privateKeyParams.Exponent.ToByteArrayUnsigned(),
                    DP = privateKeyParams.DP.ToByteArrayUnsigned(),
                    DQ = privateKeyParams.DQ.ToByteArrayUnsigned(),
                    P = privateKeyParams.P.ToByteArrayUnsigned(),
                    Q = privateKeyParams.Q.ToByteArrayUnsigned(),
                    InverseQ = privateKeyParams.QInv.ToByteArrayUnsigned()
                };
                rsa.ImportParameters(rsaParams);
                return rsa.ToXmlString(true);
            }
        }

        /// <summary>
        /// 将字符串公钥转换为xml公钥
        /// </summary>
        /// <param name="pubilcKey"></param>
        /// <returns></returns>
        private static string toXmlPublicKey(string pubilcKey)
        {
            RsaKeyParameters p =
                PublicKeyFactory.CreateKey(Convert.FromBase64String(pubilcKey)) as RsaKeyParameters;
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
            {
                RSAParameters rsaParams = new RSAParameters
                {
                    Modulus = p.Modulus.ToByteArrayUnsigned(),
                    Exponent = p.Exponent.ToByteArrayUnsigned()
                };
                rsa.ImportParameters(rsaParams);
                return rsa.ToXmlString(false);
            }
        }
    }
}
